home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume24 / gnudiff1.15 / part08 < prev    next >
Encoding:
Internet Message Format  |  1991-03-05  |  48.7 KB

  1. Subject:  v24i023:  GNU Diff, version 1.15, Part08/08
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: fe64831c 7eba4177 12fe286e cdb0fff2
  5.  
  6. Submitted-by: Paul Eggert <eggert@twinsun.com>
  7. Posting-number: Volume 24, Issue 23
  8. Archive-name: gnudiff1.15/part08
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 8 (of 8)."
  17. # Contents:  diff3.c
  18. # Wrapped by eggert@ata on Mon Jan  7 11:25:32 1991
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'diff3.c' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'diff3.c'\"
  22. else
  23. echo shar: Extracting \"'diff3.c'\" \(46642 characters\)
  24. sed "s/^X//" >'diff3.c' <<'END_OF_FILE'
  25. X/* Three-way file comparison program (diff3) for Project GNU
  26. X   Copyright (C) 1988, 1989 Free Software Foundation, Inc.
  27. X
  28. X   This program is free software; you can redistribute it and/or modify
  29. X   it under the terms of the GNU General Public License as published by
  30. X   the Free Software Foundation; either version 1, or (at your option)
  31. X   any later version.
  32. X
  33. X   This program is distributed in the hope that it will be useful,
  34. X   but WITHOUT ANY WARRANTY; without even the implied warranty of
  35. X   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  36. X   GNU General Public License for more details.
  37. X
  38. X   You should have received a copy of the GNU General Public License
  39. X   along with this program; if not, write to the Free Software
  40. X   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  41. X
  42. X
  43. X/* Written by Randy Smith */
  44. X
  45. X#ifdef __STDC__
  46. X#define VOID void
  47. X#else
  48. X#define VOID char
  49. X#endif
  50. X
  51. X/* 
  52. X * Include files.
  53. X */
  54. X#include <stdio.h>
  55. X#include <ctype.h>
  56. X#include <sys/types.h>
  57. X#include <sys/stat.h>
  58. X
  59. X#ifdef USG
  60. X#include <fcntl.h>
  61. X
  62. X/* Define needed BSD functions in terms of sysV library.  */
  63. X
  64. X#define bcmp(s1,s2,n)    memcmp((s1),(s2),(n))
  65. X#define bzero(s,n)    memset((s),0,(n))
  66. X
  67. X#ifndef XENIX
  68. X#define dup2(f,t)    (close(t),fcntl((f),F_DUPFD,(t)))
  69. X#endif
  70. X
  71. X#define vfork    fork
  72. X
  73. X#else /* not USG */
  74. X#include <sys/wait.h>
  75. X#endif /* not USG */
  76. X
  77. X#ifndef WEXITSTATUS
  78. X#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
  79. X#undef WIFEXITED /* Avoid 4.3BSD incompatibility with Posix.  */
  80. X#endif
  81. X#ifndef WIFEXITED
  82. X#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
  83. X#endif
  84. X
  85. X#ifdef sparc
  86. X/* vfork clobbers registers on the Sparc, so don't use it.  */
  87. X#define vfork fork
  88. X#endif
  89. X
  90. X/*
  91. X * Internal data structures and macros for the diff3 program; includes
  92. X * data structures for both diff3 diffs and normal diffs.
  93. X */
  94. X
  95. X/*
  96. X * Different files within a diff
  97. X */
  98. X#define    FILE0    0
  99. X#define    FILE1    1
  100. X#define    FILE2    2
  101. X
  102. X/*
  103. X * Three way diffs are build out of two two-way diffs; the file which
  104. X * the two two-way diffs share is:
  105. X */
  106. X#define    FILEC    FILE0
  107. X
  108. X/* The ranges are indexed by */
  109. X#define    START    0
  110. X#define    END    1
  111. X
  112. Xenum diff_type {
  113. X  ERROR,            /* Should not be used */
  114. X  ADD,                /* Two way diff add */
  115. X  CHANGE,            /* Two way diff change */
  116. X  DELETE,            /* Two way diff delete */
  117. X  DIFF_ALL,            /* All three are different */
  118. X  DIFF_1ST,            /* Only the first is different */
  119. X  DIFF_2ND,            /* Only the second */
  120. X  DIFF_3RD            /* Only the third */
  121. X};
  122. X
  123. X/* Two-way diff */
  124. Xstruct diff_block {
  125. X  int ranges[2][2];            /* Ranges are inclusive */
  126. X  char **lines[2];        /* The actual lines (may contain nulls) */
  127. X  int *lengths[2];        /* Line lengths (including newlines, if any) */
  128. X  struct diff_block *next;
  129. X};
  130. X
  131. X/* Three-way diff */
  132. X
  133. Xstruct diff3_block {
  134. X  enum diff_type correspond;    /* Type of diff */
  135. X  int ranges[3][2];            /* Ranges are inclusive */
  136. X  char **lines[3];        /* The actual lines (may contain nulls) */
  137. X  int *lengths[3];        /* Line lengths (including newlines, if any) */
  138. X  struct diff3_block *next;
  139. X};
  140. X
  141. X/*
  142. X * Access the ranges on a diff block.
  143. X */
  144. X#define    D_LOWLINE(diff, filenum)    \
  145. X  ((diff)->ranges[filenum][START])
  146. X#define    D_HIGHLINE(diff, filenum)    \
  147. X  ((diff)->ranges[filenum][END])
  148. X#define    D_NUMLINES(diff, filenum)    \
  149. X  (D_HIGHLINE((diff), (filenum)) - D_LOWLINE((diff), (filenum)) + 1)
  150. X
  151. X/*
  152. X * Access the line numbers in a file in a diff by relative line
  153. X * numbers (i.e. line number within the diff itself).  Note that these
  154. X * are lvalues and can be used for assignment.
  155. X */
  156. X#define    D_RELNUM(diff, filenum, linenum)    \
  157. X  (*((diff)->lines[filenum] + linenum))
  158. X#define    D_RELLEN(diff, filenum, linenum)    \
  159. X  (*((diff)->lengths[filenum] + linenum))
  160. X
  161. X/*
  162. X * And get at them directly, when that should be necessary.
  163. X */
  164. X#define    D_LINEARRAY(diff, filenum)    \
  165. X  ((diff)->lines[filenum])
  166. X#define    D_LENARRAY(diff, filenum)    \
  167. X  ((diff)->lengths[filenum])
  168. X
  169. X/*
  170. X * Next block.
  171. X */
  172. X#define    D_NEXT(diff)    ((diff)->next)
  173. X
  174. X/*
  175. X * Access the type of a diff3 block.
  176. X */
  177. X#define    D3_TYPE(diff)    ((diff)->correspond)
  178. X
  179. X/*
  180. X * Line mappings based on diffs.  The first maps off the top of the
  181. X * diff, the second off of the bottom.
  182. X */
  183. X#define    D_HIGH_MAPLINE(diff, fromfile, tofile, lineno)    \
  184. X  ((lineno)                        \
  185. X   - D_HIGHLINE ((diff), (fromfile))            \
  186. X   + D_HIGHLINE ((diff), (tofile)))
  187. X
  188. X#define    D_LOW_MAPLINE(diff, fromfile, tofile, lineno)    \
  189. X  ((lineno)                        \
  190. X   - D_LOWLINE ((diff), (fromfile))            \
  191. X   + D_LOWLINE ((diff), (tofile)))
  192. X
  193. X/*
  194. X * General memory allocation function.
  195. X */
  196. X#define    ALLOCATE(number, type)    \
  197. X  (type *) xmalloc ((number) * sizeof (type))
  198. X
  199. X/*
  200. X * Options variables for flags set on command line.
  201. X *
  202. X * ALWAYS_TEXT: Treat all files as text files; never treat as binary.
  203. X *
  204. X * EDSCRIPT: Write out an ed script instead of the standard diff3 format.
  205. X *
  206. X * FLAGGING: Indicates that in the case of overlapping diffs (type
  207. X * DIFF_ALL), the lines which would normally be deleted from file 1
  208. X * should be preserved with a special flagging mechanism.
  209. X *
  210. X * DONT_WRITE_OVERLAP: 1 if information for overlapping diffs should
  211. X * not be output.
  212. X *
  213. X * DONT_WRITE_SIMPLE: 1 if information for non-overlapping diffs
  214. X * should not be output. 
  215. X *
  216. X * FINALWRITE: 1 if a :wq should be included at the end of the script
  217. X * to write out the file being edited.
  218. X *
  219. X * MERGE: output a merged file.
  220. X */
  221. Xint always_text;
  222. Xint edscript;
  223. Xint flagging;
  224. Xint dont_write_overlap;
  225. Xint dont_write_simple;
  226. Xint finalwrite;
  227. Xint merge;
  228. X
  229. Xextern int optind;
  230. X
  231. Xchar *argv0;
  232. X
  233. X/*
  234. X * Forward function declarations.
  235. X */
  236. Xstruct diff_block *process_diff ();
  237. Xstruct diff3_block *make_3way_diff ();
  238. Xvoid output_diff3 ();
  239. Xint output_diff3_edscript ();
  240. Xint output_diff3_merge ();
  241. Xvoid usage ();
  242. X
  243. Xstruct diff3_block *using_to_diff3_block ();
  244. Xint copy_stringlist ();
  245. Xstruct diff3_block *create_diff3_block ();
  246. Xint compare_line_list ();
  247. X
  248. Xchar *read_diff ();
  249. Xenum diff_type process_diff_control ();
  250. Xchar *scan_diff_line ();
  251. X
  252. Xstruct diff3_block *reverse_diff3_blocklist ();
  253. X
  254. XVOID *xmalloc ();
  255. XVOID *xrealloc ();
  256. X
  257. Xchar diff_program[] = DIFF_PROGRAM;
  258. X
  259. X/*
  260. X * Main program.  Calls diff twice on two pairs of input files,
  261. X * combines the two diffs, and outputs them.
  262. X */
  263. Xmain (argc, argv)
  264. X     int argc;
  265. X     char **argv;
  266. X{
  267. X  int c, i;
  268. X  int mapping[3];
  269. X  int rev_mapping[3];
  270. X  int incompat;
  271. X  int overlaps_found;
  272. X  struct diff_block *thread1, *thread2;
  273. X  struct diff3_block *diff;
  274. X  int tag_count = 0;
  275. X  /* Element 0 is for file 0, element 1 is for file 2.  */
  276. X  char *tag_strings[2];
  277. X  extern char *optarg;
  278. X  char *commonname;
  279. X  struct stat statb;
  280. X
  281. X  incompat = 0;
  282. X  tag_strings[0] = tag_strings[1] = 0;
  283. X
  284. X  argv0 = argv[0];
  285. X  
  286. X  while ((c = getopt (argc, argv, "aeimx3EXL:")) != EOF)
  287. X    {
  288. X      switch (c)
  289. X    {
  290. X    case 'a':
  291. X      always_text = 1;
  292. X      break;
  293. X    case 'x':
  294. X      dont_write_simple = 1;
  295. X      incompat++;
  296. X      break;
  297. X    case '3':
  298. X      dont_write_overlap = 1;
  299. X      incompat++;
  300. X      break;
  301. X    case 'i':
  302. X      finalwrite = 1;
  303. X      break;
  304. X    case 'm':
  305. X      merge = 1;
  306. X      break;
  307. X    case 'X':
  308. X      dont_write_simple = 1;
  309. X      /* Falls through */
  310. X    case 'E':
  311. X      flagging = 1;
  312. X      /* Falls through */
  313. X    case 'e':
  314. X      incompat++;
  315. X      break;
  316. X    case 'L':
  317. X      /* Handle one or two -L arguments.  */
  318. X      if (tag_count < 2)
  319. X        {
  320. X          tag_strings[tag_count++] = optarg;
  321. X          break;
  322. X        }
  323. X      /* Falls through */
  324. X    case '?':
  325. X    default:
  326. X      usage ();
  327. X      /* NOTREACHED */
  328. X    }
  329. X    }
  330. X
  331. X  edscript = incompat & ~merge;  /* -eExX3 without -m implies ed script.  */
  332. X  flagging |= ~incompat & merge;  /* -m without -eExX3 implies -E.  */
  333. X
  334. X  if (incompat > 1  /* Ensure at most one of -eExX3.  */
  335. X      || finalwrite & (~incompat | merge)
  336. X        /* -i needs one of -eExX3; -i -m would rewrite input file.  */
  337. X      || tag_count && ! flagging /* -L requires one of -EX.  */
  338. X      || argc - optind != 3)
  339. X    usage ();
  340. X
  341. X  if (tag_strings[0] == 0)
  342. X    tag_strings[0] = argv[optind];
  343. X  if (tag_strings[1] == 0)
  344. X    tag_strings[1] = argv[optind + 2];
  345. X
  346. X  if (*argv[optind] == '-' && *(argv[optind] + 1) == '\0')
  347. X    {
  348. X      /* Sigh.  We've got standard input as the first arg. We can't */
  349. X      /* call diff twice on stdin */
  350. X      if (! strcmp (argv[optind + 1], "-") || ! strcmp (argv[optind + 2], "-"))
  351. X    fatal ("`-' specified for more than one input file");
  352. X      mapping[0] = 1;
  353. X      mapping[1] = 2;
  354. X      mapping[2] = 0;
  355. X      rev_mapping[1] = 0;
  356. X      rev_mapping[2] = 1;
  357. X      rev_mapping[0] = 2;
  358. X    }
  359. X  else
  360. X    {
  361. X      /* Normal, what you'd expect */
  362. X      mapping[0] = 0;
  363. X      mapping[1] = 1;
  364. X      mapping[2] = 2;
  365. X      rev_mapping[0] = 0;
  366. X      rev_mapping[1] = 1;
  367. X      rev_mapping[2] = 2;
  368. X    }
  369. X
  370. X  for (i = 0; i < 3; i++)
  371. X    if (argv[optind + i][0] != '-' || argv[optind + i][1] != '\0')
  372. X      if (stat (argv[optind + i], &statb) < 0)
  373. X    perror_with_exit (argv[optind + i]);
  374. X      else if ((statb.st_mode & S_IFMT) == S_IFDIR)
  375. X    {
  376. X      fprintf (stderr, "%s: %s: Is a directory\n", argv0,
  377. X           argv[optind + i]);
  378. X      exit (2);
  379. X    }
  380. X  
  381. X
  382. X  commonname = argv[optind + rev_mapping[0]];
  383. X  thread1 = process_diff (commonname, argv[optind + rev_mapping[1]]);
  384. X  thread2 = process_diff (commonname, argv[optind + rev_mapping[2]]);
  385. X  diff = make_3way_diff (thread1, thread2);
  386. X  if (edscript)
  387. X    overlaps_found
  388. X      = output_diff3_edscript (stdout, diff, mapping, rev_mapping,
  389. X                   tag_strings[0], argv[optind+1], tag_strings[1]);
  390. X  else if (merge)
  391. X    {
  392. X      if (! freopen (commonname, "r", stdin))
  393. X    perror_with_exit (commonname);
  394. X      overlaps_found
  395. X    = output_diff3_merge (stdin, stdout, diff, mapping, rev_mapping,
  396. X                  tag_strings[0], argv[optind+1], tag_strings[1]);
  397. X      if (ferror (stdin))
  398. X    fatal ("read error");
  399. X    }
  400. X  else
  401. X    {
  402. X      output_diff3 (stdout, diff, mapping, rev_mapping);
  403. X      overlaps_found = 0;
  404. X    }
  405. X
  406. X  if (ferror (stdout) || fflush (stdout) != 0)
  407. X    fatal ("write error");
  408. X  exit (overlaps_found);
  409. X}
  410. X      
  411. X/*
  412. X * Explain, patiently and kindly, how to use this program.  Then exit.
  413. X */
  414. Xvoid
  415. Xusage ()
  416. X{
  417. X  fprintf (stderr, "Usage:\t%s [-exEX3 [-i | -m] [-L label1 -L label3]] file1 file2 file3\n",
  418. X       argv0);
  419. X  fprintf (stderr, "\tOnly one of [exEX3] allowed\n");
  420. X  exit (2);
  421. X}
  422. X
  423. X/*
  424. X * Routines that combine the two diffs together into one.  The
  425. X * algorithm used follows:
  426. X *
  427. X *   File0 is shared in common between the two diffs.
  428. X *   Diff01 is the diff between 0 and 1.
  429. X *   Diff02 is the diff between 0 and 2.
  430. X *
  431. X *     1) Find the range for the first block in File0.
  432. X *          a) Take the lowest of the two ranges (in File0) in the two
  433. X *             current blocks (one from each diff) as being the low
  434. X *             water mark.  Assign the upper end of this block as
  435. X *             being the high water mark and move the current block up
  436. X *             one.  Mark the block just moved over as to be used.
  437. X *        b) Check the next block in the diff that the high water
  438. X *             mark is *not* from.  
  439. X *           
  440. X *           *If* the high water mark is above
  441. X *             the low end of the range in that block, 
  442. X * 
  443. X *               mark that block as to be used and move the current
  444. X *                 block up.  Set the high water mark to the max of
  445. X *                 the high end of this block and the current.  Repeat b.
  446. X * 
  447. X *       2) Find the corresponding ranges in Files1 (from the blocks
  448. X *          in diff01; line per line outside of diffs) and in File2.
  449. X *          Create a diff3_block, reserving space as indicated by the ranges.
  450. X *        
  451. X *     3) Copy all of the pointers for file0 in.  At least for now,
  452. X *          do bcmp's between corresponding strings in the two diffs.
  453. X *        
  454. X *     4) Copy all of the pointers for file1 and 2 in.  Get what you
  455. X *          need from file0 (when there isn't a diff block, it's
  456. X *          identical to file0 within the range between diff blocks).
  457. X *        
  458. X *     5) If the diff blocks you used came from only one of the two
  459. X *         strings of diffs, then that file (i.e. the one other than
  460. X *         file 0 in that diff) is the odd person out.  If you used
  461. X *         diff blocks from both sets, check to see if files 1 and 2 match:
  462. X *        
  463. X *            Same number of lines?  If so, do a set of bcmp's (if a
  464. X *          bcmp matches; copy the pointer over; it'll be easier later
  465. X *          if you have to do any compares).  If they match, 1 & 2 are
  466. X *          the same.  If not, all three different.
  467. X * 
  468. X *   Then you do it again, until you run out of blocks. 
  469. X * 
  470. X */
  471. X
  472. X/* 
  473. X * This routine makes a three way diff (chain of diff3_block's) from two
  474. X * two way diffs (chains of diff_block's).  It is assumed that each of
  475. X * the two diffs passed are off of the same file (i.e. that each of the
  476. X * diffs were made "from" the same file).  The three way diff pointer
  477. X * returned will have numbering 0--the common file, 1--the other file
  478. X * in diff1, and 2--the other file in diff2.
  479. X */
  480. Xstruct diff3_block *
  481. Xmake_3way_diff (thread1, thread2)
  482. X     struct diff_block *thread1, *thread2;
  483. X{
  484. X/*
  485. X * This routine works on the two diffs passed to it as threads.
  486. X * Thread number 0 is diff1, thread number 1 is diff2.  The USING
  487. X * array is set to the base of the list of blocks to be used to
  488. X * construct each block of the three way diff; if no blocks from a
  489. X * particular thread are to be used, that element of the using array
  490. X * is set to 0.  The elements LAST_USING array are set to the last
  491. X * elements on each of the using lists.
  492. X *
  493. X * The HIGH_WATER_MARK is set to the highest line number in File 0
  494. X * described in any of the diffs in either of the USING lists.  The
  495. X * HIGH_WATER_THREAD names the thread.  Similarly the BASE_WATER_MARK
  496. X * and BASE_WATER_THREAD describe the lowest line number in File 0
  497. X * described in any of the diffs in either of the USING lists.  The
  498. X * HIGH_WATER_DIFF is the diff from which the HIGH_WATER_MARK was
  499. X * taken. 
  500. X *
  501. X * The HIGH_WATER_DIFF should always be equal to LAST_USING
  502. X * [HIGH_WATER_THREAD].  The OTHER_DIFF is the next diff to check for
  503. X * higher water, and should always be equal to
  504. X * CURRENT[HIGH_WATER_THREAD ^ 0x1].  The OTHER_THREAD is the thread
  505. X * in which the OTHER_DIFF is, and hence should always be equal to
  506. X * HIGH_WATER_THREAD ^ 0x1.
  507. X *
  508. X * The variable LAST_DIFF is kept set to the last diff block produced
  509. X * by this routine, for line correspondence purposes between that diff
  510. X * and the one currently being worked on.  It is initialized to
  511. X * ZERO_DIFF before any blocks have been created.
  512. X */
  513. X
  514. X  struct diff_block
  515. X    *using[2],
  516. X    *last_using[2],
  517. X    *current[2];
  518. X
  519. X  int
  520. X    high_water_mark;
  521. X
  522. X  int
  523. X    high_water_thread,
  524. X    base_water_thread,
  525. X    other_thread;
  526. X
  527. X  struct diff_block
  528. X    *high_water_diff,
  529. X    *other_diff;
  530. X
  531. X  struct diff3_block
  532. X    *result,
  533. X    *tmpblock,
  534. X    *result_last,
  535. X    *last_diff;
  536. X
  537. X  static struct diff3_block zero_diff = {
  538. X      ERROR,
  539. X      { {0, 0}, {0, 0}, {0, 0} },
  540. X      { (char **) 0, (char **) 0, (char **) 0 },
  541. X      { (int *) 0, (int *) 0, (int *) 0 },
  542. X      (struct diff3_block *) 0
  543. X      };
  544. X
  545. X  /* Initialization */
  546. X  result = result_last = (struct diff3_block *) 0;
  547. X  current[0] = thread1; current[1] = thread2;
  548. X  last_diff = &zero_diff;
  549. X
  550. X  /* Sniff up the threads until we reach the end */
  551. X
  552. X  while (current[0] || current[1])
  553. X    {
  554. X      using[0] = using[1] = last_using[0] = last_using[1] =
  555. X    (struct diff_block *) 0;
  556. X
  557. X      /* Setup low and high water threads, diffs, and marks.  */
  558. X      if (!current[0])
  559. X    base_water_thread = 1;
  560. X      else if (!current[1])
  561. X    base_water_thread = 0;
  562. X      else
  563. X    base_water_thread =
  564. X      (D_LOWLINE (current[0], FILE0) > D_LOWLINE (current[1], FILE0));
  565. X
  566. X      high_water_thread = base_water_thread;
  567. X      
  568. X      high_water_diff = current[high_water_thread];
  569. X    
  570. X#if 0
  571. X      /* low and high waters start off same diff */
  572. X      base_water_mark = D_LOWLINE (high_water_diff, FILE0);
  573. X#endif
  574. X
  575. X      high_water_mark = D_HIGHLINE (high_water_diff, FILE0);
  576. X
  577. X      /* Make the diff you just got info from into the using class */
  578. X      using[high_water_thread]
  579. X    = last_using[high_water_thread]
  580. X    = high_water_diff;
  581. X      current[high_water_thread] = high_water_diff->next;
  582. X      last_using[high_water_thread]->next
  583. X    = (struct diff_block *) 0;
  584. X
  585. X      /* And mark the other diff */
  586. X      other_thread = high_water_thread ^ 0x1;
  587. X      other_diff = current[other_thread];
  588. X
  589. X      /* Shuffle up the ladder, checking the other diff to see if it
  590. X         needs to be incorporated */
  591. X      while (other_diff
  592. X         && D_LOWLINE (other_diff, FILE0) <= high_water_mark + 1)
  593. X    {
  594. X
  595. X      /* Incorporate this diff into the using list.  Note that
  596. X         this doesn't take it off the current list */
  597. X      if (using[other_thread])
  598. X        last_using[other_thread]->next = other_diff;
  599. X      else
  600. X        using[other_thread] = other_diff;
  601. X      last_using[other_thread] = other_diff;
  602. X
  603. X      /* Take it off the current list.  Note that this following
  604. X         code assumes that other_diff enters it equal to
  605. X         current[high_water_thread ^ 0x1] */
  606. X      current[other_thread]
  607. X        = current[other_thread]->next;
  608. X      other_diff->next
  609. X        = (struct diff_block *) 0;
  610. X
  611. X      /* Set the high_water stuff
  612. X         If this comparison is equal, then this is the last pass
  613. X         through this loop; since diff blocks within a given
  614. X         thread cannot overlap, the high_water_mark will be
  615. X         *below* the range_start of either of the next diffs. */
  616. X
  617. X      if (high_water_mark < D_HIGHLINE (other_diff, FILE0))
  618. X        {
  619. X          high_water_thread ^= 1;
  620. X          high_water_diff = other_diff;
  621. X          high_water_mark = D_HIGHLINE (other_diff, FILE0);
  622. X        }
  623. X
  624. X      /* Set the other diff */
  625. X      other_thread = high_water_thread ^ 0x1;
  626. X      other_diff = current[other_thread];
  627. X    }
  628. X
  629. X      /* The using lists contain a list of all of the blocks to be
  630. X         included in this diff3_block.  Create it.  */
  631. X
  632. X      tmpblock = using_to_diff3_block (using, last_using,
  633. X                       base_water_thread, high_water_thread,
  634. X                       last_diff);
  635. X
  636. X      if (!tmpblock)
  637. X    fatal ("internal: screwup in format of diff blocks");
  638. X
  639. X      /* Put it on the list */
  640. X      if (result)
  641. X    result_last->next = tmpblock;
  642. X      else
  643. X    result = tmpblock;
  644. X      result_last = tmpblock;
  645. X
  646. X      /* Setup corresponding lines correctly */
  647. X      last_diff = tmpblock;
  648. X    }
  649. X  return result;
  650. X}
  651. X
  652. X/*
  653. X * using_to_diff3_block:
  654. X *   This routine takes two lists of blocks (from two separate diff
  655. X * threads) and puts them together into one diff3 block.
  656. X * It then returns a pointer to this diff3 block or 0 for failure.
  657. X *
  658. X * All arguments besides using are for the convenience of the routine;
  659. X * they could be derived from the using array.
  660. X * LAST_USING is a pair of pointers to the last blocks in the using
  661. X * structure.
  662. X * LOW_THREAD and HIGH_THREAD tell which threads contain the lowest
  663. X * and highest line numbers for File0.
  664. X * last_diff contains the last diff produced in the calling routine.
  665. X * This is used for lines mappings which would still be identical to
  666. X * the state that diff ended in.
  667. X *
  668. X * A distinction should be made in this routine between the two diffs
  669. X * that are part of a normal two diff block, and the three diffs that
  670. X * are part of a diff3_block.
  671. X */
  672. Xstruct diff3_block *
  673. Xusing_to_diff3_block (using, last_using, low_thread, high_thread, last_diff)
  674. X     struct diff_block
  675. X       *using[2],
  676. X       *last_using[2];
  677. X     int low_thread, high_thread;
  678. X     struct diff3_block *last_diff;
  679. X{
  680. X  int lowc, highc, low1, high1, low2, high2;
  681. X  struct diff3_block *result;
  682. X  struct diff_block *ptr;
  683. X  int i;
  684. X  int current0line;
  685. X  
  686. X  /* Find the range in file0 */
  687. X  lowc = using[low_thread]->ranges[0][START];
  688. X  highc = last_using[high_thread]->ranges[0][END];
  689. X
  690. X  /* Find the ranges in the other files.
  691. X     If using[x] is null, that means that the file to which that diff
  692. X     refers is equivalent to file 0 over this range */
  693. X  
  694. X  if (using[0])
  695. X    {
  696. X      low1 = D_LOW_MAPLINE (using[0], FILE0, FILE1, lowc);
  697. X      high1 = D_HIGH_MAPLINE (last_using[0], FILE0, FILE1, highc); 
  698. X    }
  699. X  else
  700. X    {
  701. X      low1 = D_HIGH_MAPLINE (last_diff, FILEC, FILE1, lowc);
  702. X      high1 = D_HIGH_MAPLINE (last_diff, FILEC, FILE1, highc);
  703. X    }
  704. X
  705. X  /*
  706. X   * Note that in the following, we use file 1 relative to the diff,
  707. X   * and file 2 relative to the corresponding lines struct.
  708. X   */
  709. X  if (using[1])
  710. X    {
  711. X      low2 = D_LOW_MAPLINE (using[1], FILE0, FILE1, lowc);
  712. X      high2 = D_HIGH_MAPLINE (last_using[1], FILE0, FILE1, highc); 
  713. X    }
  714. X  else
  715. X    {
  716. X      low2 = D_HIGH_MAPLINE (last_diff, FILEC, FILE2, lowc);
  717. X      high2 = D_HIGH_MAPLINE (last_diff, FILEC, FILE2, highc);
  718. X    }
  719. X
  720. X  /* Create a block with the appropriate sizes */
  721. X  result = create_diff3_block (lowc, highc, low1, high1, low2, high2);
  722. X
  723. X  /* Copy over all of the information for File 0.  Return with a zero
  724. X     if any of the compares failed. */
  725. X  for (ptr = using[0]; ptr; ptr = D_NEXT (ptr))
  726. X    {
  727. X      int result_offset = D_LOWLINE (ptr, FILE0) - lowc;
  728. X      int copy_size
  729. X    = D_HIGHLINE (ptr, FILE0) - D_LOWLINE (ptr, FILE0) + 1;
  730. X      
  731. X      if (!copy_stringlist (D_LINEARRAY (ptr, FILE0),
  732. X                D_LENARRAY (ptr, FILE0),
  733. X                D_LINEARRAY (result, FILEC) + result_offset,
  734. X                D_LENARRAY (result, FILEC) + result_offset,
  735. X                copy_size))
  736. X    return 0;
  737. X    }
  738. X
  739. X  for (ptr = using[1]; ptr; ptr = D_NEXT (ptr))
  740. X    {
  741. X      int result_offset = D_LOWLINE (ptr, FILEC) - lowc;
  742. X      int copy_size
  743. X    = D_HIGHLINE (ptr, FILEC) - D_LOWLINE (ptr, FILEC) + 1;
  744. X      
  745. X      if (!copy_stringlist (D_LINEARRAY (ptr, FILE0),
  746. X                D_LENARRAY (ptr, FILE0),
  747. X                D_LINEARRAY (result, FILEC) + result_offset,
  748. X                D_LENARRAY (result, FILEC) + result_offset,
  749. X                copy_size))
  750. X    return 0;
  751. X    }
  752. X
  753. X  /* Copy stuff for file 1.  First deal with anything that might be
  754. X     before the first diff. */
  755. X
  756. X  for (i = 0;
  757. X       i + low1 < (using[0] ? D_LOWLINE (using[0], FILE1) : high1 + 1);
  758. X       i++)
  759. X    {
  760. X      D_RELNUM (result, FILE1, i) = D_RELNUM (result, FILEC, i);
  761. X      D_RELLEN (result, FILE1, i) = D_RELLEN (result, FILEC, i);
  762. X    }
  763. X  
  764. X  for (ptr = using[0]; ptr; ptr = D_NEXT (ptr))
  765. X    {
  766. X      int result_offset = D_LOWLINE (ptr, FILE1) - low1;
  767. X      int copy_size
  768. X    = D_HIGHLINE (ptr, FILE1) - D_LOWLINE (ptr, FILE1) + 1;
  769. X
  770. X      if (!copy_stringlist (D_LINEARRAY (ptr, FILE1),
  771. X                D_LENARRAY (ptr, FILE1),
  772. X                D_LINEARRAY (result, FILE1) + result_offset,
  773. X                D_LENARRAY (result, FILE1) + result_offset,
  774. X                copy_size))
  775. X    return 0;
  776. X
  777. X      /* Catch the lines between here and the next diff */
  778. X      current0line = D_HIGHLINE (ptr, FILE0) + 1 - lowc;
  779. X      for (i = D_HIGHLINE (ptr, FILE1) + 1 - low1;
  780. X       i < (D_NEXT (ptr) ?
  781. X        D_LOWLINE (D_NEXT (ptr), FILE1) :
  782. X        high1 + 1) - low1;
  783. X       i++)
  784. X    {
  785. X      D_RELNUM (result, FILE1, i)
  786. X        = D_RELNUM (result, FILEC, current0line);
  787. X      D_RELLEN (result, FILE1, i)
  788. X        = D_RELLEN (result, FILEC, current0line++);
  789. X    }
  790. X    }
  791. X
  792. X  /* Copy stuff for file 2.  First deal with anything that might be
  793. X     before the first diff. */
  794. X
  795. X  for (i = 0;
  796. X       i + low2 < (using[1] ? D_LOWLINE (using[1], FILE1) : high2 + 1);
  797. X       i++)
  798. X    {
  799. X      D_RELNUM (result, FILE2, i) = D_RELNUM (result, FILEC, i);
  800. X      D_RELLEN (result, FILE2, i) = D_RELLEN (result, FILEC, i);
  801. X    }
  802. X  
  803. X  for (ptr = using[1]; ptr; ptr = D_NEXT (ptr))
  804. X    {
  805. X      int result_offset = D_LOWLINE (ptr, FILE1) - low2;
  806. X      int copy_size
  807. X    = D_HIGHLINE (ptr, FILE1) - D_LOWLINE (ptr, FILE1) + 1;
  808. X
  809. X      if (!copy_stringlist (D_LINEARRAY (ptr, FILE1),
  810. X                D_LENARRAY (ptr, FILE1),
  811. X                D_LINEARRAY (result, FILE2) + result_offset,
  812. X                D_LENARRAY (result, FILE2) + result_offset,
  813. X                copy_size))
  814. X    return 0;
  815. X
  816. X      /* Catch the lines between here and the next diff */
  817. X      current0line = D_HIGHLINE (ptr, FILE0) + 1 - lowc;
  818. X      for (i = D_HIGHLINE (ptr, FILE1) + 1 - low2;
  819. X       i < (D_NEXT (ptr) ?
  820. X        D_LOWLINE (D_NEXT (ptr), FILE1) :
  821. X        high2 + 1) - low2;
  822. X       i++)
  823. X    {
  824. X      D_RELNUM (result, FILE2, i)
  825. X        = D_RELNUM (result, FILEC, current0line);
  826. X      D_RELLEN (result, FILE2, i)
  827. X        = D_RELLEN (result, FILEC, current0line++);
  828. X    }
  829. X    }
  830. X
  831. X  /* Set correspond */
  832. X  if (!using[0])
  833. X    D3_TYPE (result) = DIFF_3RD;
  834. X  else if (!using[1])
  835. X    D3_TYPE (result) = DIFF_2ND;
  836. X  else
  837. X    {
  838. X      int nl1
  839. X    = D_HIGHLINE (result, FILE1) - D_LOWLINE (result, FILE1) + 1;
  840. X      int nl2
  841. X    = D_HIGHLINE (result, FILE2) - D_LOWLINE (result, FILE2) + 1;
  842. X
  843. X      if (nl1 != nl2
  844. X      || !compare_line_list (D_LINEARRAY (result, FILE1),
  845. X                 D_LENARRAY (result, FILE1),
  846. X                 D_LINEARRAY (result, FILE2),
  847. X                 D_LENARRAY (result, FILE2),
  848. X                 nl1))
  849. X    D3_TYPE (result) = DIFF_ALL;
  850. X      else
  851. X    D3_TYPE (result) = DIFF_1ST;
  852. X    }
  853. X  
  854. X  return result;
  855. X}
  856. X
  857. X/*
  858. X * This routine copies pointers from a list of strings to a different list
  859. X * of strings.  If a spot in the second list is already filled, it
  860. X * makes sure that it is filled with the same string; if not it
  861. X * returns 0, the copy incomplete.
  862. X * Upon successful completion of the copy, it returns 1.
  863. X */
  864. Xint
  865. Xcopy_stringlist (fromptrs, fromlengths, toptrs, tolengths, copynum)
  866. X     char *fromptrs[], *toptrs[];
  867. X     int *fromlengths, *tolengths;
  868. X     int copynum;
  869. X{
  870. X  register char
  871. X    **f = fromptrs,
  872. X    **t = toptrs;
  873. X  register int
  874. X    *fl = fromlengths,
  875. X    *tl = tolengths;
  876. X  
  877. X  while (copynum--)
  878. X    {
  879. X      if (*t)
  880. X    { if (*fl != *tl || bcmp (*f, *t, *fl)) return 0; }
  881. X      else
  882. X    { *t = *f ; *tl = *fl; }
  883. X
  884. X      t++; f++; tl++; fl++;
  885. X    }
  886. X  return 1;
  887. X}
  888. X
  889. X/*
  890. X * Create a diff3_block, with ranges as specified in the arguments.
  891. X * Allocate the arrays for the various pointers (and zero them) based
  892. X * on the arguments passed.  Return the block as a result.
  893. X */
  894. Xstruct diff3_block *
  895. Xcreate_diff3_block (low0, high0, low1, high1, low2, high2)
  896. X     register int low0, high0, low1, high1, low2, high2;
  897. X{
  898. X  struct diff3_block *result = ALLOCATE (1, struct diff3_block);
  899. X  int numlines;
  900. X
  901. X  D3_TYPE (result) = ERROR;
  902. X  D_NEXT (result) = 0;
  903. X
  904. X  /* Assign ranges */
  905. X  D_LOWLINE (result, FILE0) = low0;
  906. X  D_HIGHLINE (result, FILE0) = high0;
  907. X  D_LOWLINE (result, FILE1) = low1;
  908. X  D_HIGHLINE (result, FILE1) = high1;
  909. X  D_LOWLINE (result, FILE2) = low2;
  910. X  D_HIGHLINE (result, FILE2) = high2;
  911. X
  912. X  /* Allocate and zero space */
  913. X  numlines = D_NUMLINES (result, FILE0);
  914. X  if (numlines)
  915. X    {
  916. X      D_LINEARRAY (result, FILE0) = ALLOCATE (numlines, char *);
  917. X      D_LENARRAY (result, FILE0) = ALLOCATE (numlines, int);
  918. X      bzero (D_LINEARRAY (result, FILE0), (numlines * sizeof (char *)));
  919. X      bzero (D_LENARRAY (result, FILE0), (numlines * sizeof (int)));
  920. X    }
  921. X  else
  922. X    {
  923. X      D_LINEARRAY (result, FILE0) = (char **) 0;
  924. X      D_LENARRAY (result, FILE0) = (int *) 0;
  925. X    }
  926. X
  927. X  numlines = D_NUMLINES (result, FILE1);
  928. X  if (numlines)
  929. X    {
  930. X      D_LINEARRAY (result, FILE1) = ALLOCATE (numlines, char *);
  931. X      D_LENARRAY (result, FILE1) = ALLOCATE (numlines, int);
  932. X      bzero (D_LINEARRAY (result, FILE1), (numlines * sizeof (char *)));
  933. X      bzero (D_LENARRAY (result, FILE1), (numlines * sizeof (int)));
  934. X    }
  935. X  else
  936. X    {
  937. X      D_LINEARRAY (result, FILE1) = (char **) 0;
  938. X      D_LENARRAY (result, FILE1) = (int *) 0;
  939. X    }
  940. X
  941. X  numlines = D_NUMLINES (result, FILE2);
  942. X  if (numlines)
  943. X    {
  944. X      D_LINEARRAY (result, FILE2) = ALLOCATE (numlines, char *);
  945. X      D_LENARRAY (result, FILE2) = ALLOCATE (numlines, int);
  946. X      bzero (D_LINEARRAY (result, FILE2), (numlines * sizeof (char *)));
  947. X      bzero (D_LENARRAY (result, FILE2), (numlines * sizeof (int)));
  948. X    }
  949. X  else
  950. X    {
  951. X      D_LINEARRAY (result, FILE2) = (char **) 0;
  952. X      D_LENARRAY (result, FILE2) = (int *) 0;
  953. X    }
  954. X
  955. X  /* Return */
  956. X  return result;
  957. X}
  958. X
  959. X/*
  960. X * Compare two lists of lines of text.
  961. X * Return 1 if they are equivalent, 0 if not.
  962. X */
  963. Xint
  964. Xcompare_line_list (list1, lengths1, list2, lengths2, nl)
  965. X     char *list1[], *list2[];
  966. X     int *lengths1, *lengths2;
  967. X     int nl;
  968. X{
  969. X  char
  970. X    **l1 = list1,
  971. X    **l2 = list2;
  972. X  int
  973. X    *lgths1 = lengths1,
  974. X    *lgths2 = lengths2;
  975. X  
  976. X  while (nl--)
  977. X    if (!*l1 || !*l2 || *lgths1 != *lgths2++
  978. X    || bcmp (*l1++, *l2++, *lgths1++))
  979. X      return 0;
  980. X  return 1;
  981. X}
  982. X
  983. X/* 
  984. X * Routines to input and parse two way diffs.
  985. X */
  986. X
  987. Xextern char **environ;
  988. X
  989. X#define    DIFF_CHUNK_SIZE    10000
  990. X
  991. Xstruct diff_block *
  992. Xprocess_diff (filea, fileb)
  993. X     char *filea, *fileb;
  994. X{
  995. X  char *diff_contents;
  996. X  char *diff_limit;
  997. X  char *scan_diff;
  998. X  enum diff_type dt;
  999. X  int i;
  1000. X  struct diff_block *block_list, *block_list_end, *bptr;
  1001. X
  1002. X  diff_limit = read_diff (filea, fileb, &diff_contents);
  1003. X  scan_diff = diff_contents;
  1004. X  bptr = block_list_end = block_list = (struct diff_block *) 0;
  1005. X
  1006. X  while (scan_diff < diff_limit)
  1007. X    {
  1008. X      bptr = ALLOCATE (1, struct diff_block);
  1009. X      bptr->next = 0;
  1010. X      bptr->lines[0] = bptr->lines[1] = (char **) 0;
  1011. X      bptr->lengths[0] = bptr->lengths[1] = (int *) 0;
  1012. X      
  1013. X      dt = process_diff_control (&scan_diff, bptr);
  1014. X      if (dt == ERROR || *scan_diff != '\n')
  1015. X    {
  1016. X      fprintf (stderr, "%s: diff error: ", argv0);
  1017. X      do
  1018. X        {
  1019. X          putc (*scan_diff, stderr);
  1020. X        }
  1021. X      while (*scan_diff++ != '\n');
  1022. X      exit (2);
  1023. X    }
  1024. X      scan_diff++;
  1025. X      
  1026. X      /* Force appropriate ranges to be null, if necessary */
  1027. X      switch (dt)
  1028. X    {
  1029. X    case ADD:
  1030. X      bptr->ranges[0][0]++;
  1031. X      break;
  1032. X    case DELETE:
  1033. X      bptr->ranges[1][0]++;
  1034. X      break;
  1035. X    case CHANGE:
  1036. X      break;
  1037. X    default:
  1038. X      fatal ("internal: Bad diff type in process_diff");
  1039. X      break;
  1040. X    }
  1041. X      
  1042. X      /* Allocate space for the pointers for the lines from filea, and
  1043. X     parcel them out among these pointers */
  1044. X      if (dt != ADD)
  1045. X    {
  1046. X      bptr->lines[0] = ALLOCATE ((bptr->ranges[0][END]
  1047. X                      - bptr->ranges[0][START] + 1),
  1048. X                     char *);
  1049. X      bptr->lengths[0] = ALLOCATE ((bptr->ranges[0][END]
  1050. X                    - bptr->ranges[0][START] + 1),
  1051. X                       int);
  1052. X      for (i = 0; i <= (bptr->ranges[0][END]
  1053. X                - bptr->ranges[0][START]); i++)
  1054. X        scan_diff = scan_diff_line (scan_diff,
  1055. X                    &(bptr->lines[0][i]),
  1056. X                    &(bptr->lengths[0][i]),
  1057. X                    diff_limit,
  1058. X                    '<');
  1059. X    }
  1060. X      
  1061. X      /* Get past the separator for changes */
  1062. X      if (dt == CHANGE)
  1063. X    {
  1064. X      if (strncmp (scan_diff, "---\n", 4))
  1065. X        fatal ("Bad diff format: bad change separator");
  1066. X      scan_diff += 4;
  1067. X    }
  1068. X      
  1069. X      /* Allocate space for the pointers for the lines from fileb, and
  1070. X     parcel them out among these pointers */
  1071. X      if (dt != DELETE)
  1072. X    {
  1073. X      bptr->lines[1] = ALLOCATE ((bptr->ranges[1][END]
  1074. X                      - bptr->ranges[1][START] + 1),
  1075. X                     char *);
  1076. X      bptr->lengths[1] = ALLOCATE ((bptr->ranges[1][END]
  1077. X                    - bptr->ranges[1][START] + 1),
  1078. X                       int);
  1079. X      for (i = 0; i <= (bptr->ranges[1][END]
  1080. X                - bptr->ranges[1][START]); i++)
  1081. X        scan_diff = scan_diff_line (scan_diff,
  1082. X                    &(bptr->lines[1][i]),
  1083. X                    &(bptr->lengths[1][i]),
  1084. X                    diff_limit,
  1085. X                    '>');
  1086. X    }
  1087. X      
  1088. X      /* Place this block on the blocklist */
  1089. X      if (block_list_end)
  1090. X    block_list_end->next = bptr;
  1091. X      else
  1092. X    block_list = bptr;
  1093. X      
  1094. X      block_list_end = bptr;
  1095. X      
  1096. X    }
  1097. X
  1098. X  return block_list;
  1099. X}
  1100. X
  1101. X/*
  1102. X * This routine will parse a normal format diff control string.  It
  1103. X * returns the type of the diff (ERROR if the format is bad).  All of
  1104. X * the other important information is filled into to the structure
  1105. X * pointed to by db, and the string pointer (whose location is passed
  1106. X * to this routine) is updated to point beyond the end of the string
  1107. X * parsed.  Note that only the ranges in the diff_block will be set by
  1108. X * this routine.
  1109. X *
  1110. X * If some specific pair of numbers has been reduced to a single
  1111. X * number, then both corresponding numbers in the diff block are set
  1112. X * to that number.  In general these numbers are interpetted as ranges
  1113. X * inclusive, unless being used by the ADD or DELETE commands.  It is
  1114. X * assumed that these will be special cased in a superior routine.  
  1115. X */
  1116. X
  1117. Xenum diff_type
  1118. Xprocess_diff_control (string, db)
  1119. X     char **string;
  1120. X     struct diff_block *db;
  1121. X{
  1122. X  char *s = *string;
  1123. X  int holdnum;
  1124. X  enum diff_type type;
  1125. X
  1126. X/* These macros are defined here because they can use variables
  1127. X   defined in this function.  Don't try this at home kids, we're
  1128. X   trained professionals!
  1129. X
  1130. X   Also note that SKIPWHITE only recognizes tabs and spaces, and
  1131. X   that READNUM can only read positive, integral numbers */
  1132. X
  1133. X#define    SKIPWHITE(s)    { while (*s == ' ' || *s == '\t') s++; }
  1134. X#define    READNUM(s, num)    \
  1135. X    { if (!isdigit (*s)) return ERROR; holdnum = 0;    \
  1136. X      do { holdnum = (*s++ - '0' + holdnum * 10); }    \
  1137. X      while (isdigit (*s)); (num) = holdnum; }
  1138. X
  1139. X  /* Read first set of digits */
  1140. X  SKIPWHITE (s);
  1141. X  READNUM (s, db->ranges[0][START]);
  1142. X
  1143. X  /* Was that the only digit? */
  1144. X  SKIPWHITE(s);
  1145. X  if (*s == ',')
  1146. X    {
  1147. X      /* Get the next digit */
  1148. X      s++;
  1149. X      READNUM (s, db->ranges[0][END]);
  1150. X    }
  1151. X  else
  1152. X    db->ranges[0][END] = db->ranges[0][START];
  1153. X
  1154. X  /* Get the letter */
  1155. X  SKIPWHITE (s);
  1156. X  switch (*s)
  1157. X    {
  1158. X    case 'a':
  1159. X      type = ADD;
  1160. X      break;
  1161. X    case 'c':
  1162. X      type = CHANGE;
  1163. X      break;
  1164. X    case 'd':
  1165. X      type = DELETE;
  1166. X      break;
  1167. X    default:
  1168. X      return ERROR;            /* Bad format */
  1169. X    }
  1170. X  s++;                /* Past letter */
  1171. X  
  1172. X  /* Read second set of digits */
  1173. X  SKIPWHITE (s);
  1174. X  READNUM (s, db->ranges[1][START]);
  1175. X
  1176. X  /* Was that the only digit? */
  1177. X  SKIPWHITE(s);
  1178. X  if (*s == ',')
  1179. X    {
  1180. X      /* Get the next digit */
  1181. X      s++;
  1182. X      READNUM (s, db->ranges[1][END]);
  1183. X      SKIPWHITE (s);        /* To move to end */
  1184. X    }
  1185. X  else
  1186. X    db->ranges[1][END] = db->ranges[1][START];
  1187. X
  1188. X  *string = s;
  1189. X  return type;
  1190. X}
  1191. X
  1192. Xchar *
  1193. Xread_diff (filea, fileb, output_placement)
  1194. X     char *filea, *fileb;
  1195. X     char **output_placement;
  1196. X{
  1197. X  char *argv[6];
  1198. X  char **ap;
  1199. X  int fds[2];
  1200. X  char *diff_result;
  1201. X  int current_chunk_size;
  1202. X  int bytes;
  1203. X  int total;
  1204. X  int pid, w;
  1205. X  int wstatus;
  1206. X
  1207. X  ap = argv;
  1208. X  *ap++ = diff_program;
  1209. X  if (always_text)
  1210. X    *ap++ = "-a";
  1211. X  *ap++ = "--";
  1212. X  *ap++ = filea;
  1213. X  *ap++ = fileb;
  1214. X  *ap = (char *) 0;
  1215. X
  1216. X  if (pipe (fds) < 0)
  1217. X    perror_with_exit ("Pipe failed");
  1218. X
  1219. X  pid = vfork ();
  1220. X  if (pid == 0)
  1221. X    {
  1222. X      /* Child */
  1223. X      close (fds[0]);
  1224. X      if (fds[1] != fileno (stdout))
  1225. X    {
  1226. X      dup2 (fds[1], fileno (stdout));
  1227. X      close (fds[1]);
  1228. X    }
  1229. X      execve (diff_program, argv, environ);
  1230. X      /* Avoid stdio, because the parent process's buffers are inherited. */
  1231. X      write (fileno (stderr), diff_program, strlen (diff_program));
  1232. X      write (fileno (stderr), ": not found\n", 12);
  1233. X      _exit (2);
  1234. X    }
  1235. X
  1236. X  if (pid == -1)
  1237. X    perror_with_exit ("Fork failed");
  1238. X
  1239. X  close (fds[1]);        /* Prevent erroneous lack of EOF */
  1240. X  current_chunk_size = DIFF_CHUNK_SIZE;
  1241. X  diff_result = (char *) xmalloc (current_chunk_size);
  1242. X  total = 0;
  1243. X  do {
  1244. X    bytes = myread (fds[0],
  1245. X            diff_result + total,
  1246. X            current_chunk_size - total);
  1247. X    total += bytes;
  1248. X    if (total == current_chunk_size)
  1249. X      diff_result = (char *) xrealloc (diff_result, (current_chunk_size *= 2));
  1250. X  } while (bytes);
  1251. X
  1252. X  if (total != 0 && diff_result[total-1] != '\n')
  1253. X    fatal ("bad diff format; incomplete last line");
  1254. X
  1255. X  *output_placement = diff_result;
  1256. X
  1257. X  do
  1258. X    if ((w = wait (&wstatus)) == -1)
  1259. X      perror_with_exit ("Wait failed");
  1260. X  while (w != pid);
  1261. X
  1262. X  if (! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 2))
  1263. X    fatal ("Subsidiary diff failed");
  1264. X
  1265. X  return diff_result + total;
  1266. X}
  1267. X
  1268. X
  1269. X/*
  1270. X * Scan a regular diff line (consisting of > or <, followed by a
  1271. X * space, followed by text (including nulls) up to a newline.
  1272. X *
  1273. X * This next routine began life as a macro and many parameters in it
  1274. X * are used as call-by-reference values.
  1275. X */
  1276. Xchar *
  1277. Xscan_diff_line (scan_ptr, set_start, set_length, limit, firstchar)
  1278. X     char *scan_ptr, **set_start;
  1279. X     int *set_length;
  1280. X     char *limit;
  1281. X     char firstchar;
  1282. X{
  1283. X  char *line_ptr;
  1284. X
  1285. X  if (!(scan_ptr[0] == (firstchar)
  1286. X    && scan_ptr[1] == ' '))
  1287. X    fatal ("Bad diff format; incorrect leading line chars");
  1288. X
  1289. X  *set_start = line_ptr = scan_ptr + 2;
  1290. X  while (*line_ptr++ != '\n')
  1291. X    ;
  1292. X
  1293. X  /* Include newline if the original line ended in a newline,
  1294. X     or if an edit script is being generated.
  1295. X     Copy any missing newline message to stderr if an edit script is being
  1296. X     generated, because edit scripts cannot handle missing newlines.
  1297. X     Return the beginning of the next line.  */
  1298. X  *set_length = line_ptr - *set_start;
  1299. X  if (line_ptr < limit && *line_ptr == '\\')
  1300. X    {
  1301. X      if (edscript)
  1302. X    fprintf (stderr, "%s:", argv0);
  1303. X      else
  1304. X    --*set_length;
  1305. X      line_ptr++;
  1306. X      do
  1307. X    {
  1308. X      if (edscript)
  1309. X        putc (*line_ptr, stderr);
  1310. X    }
  1311. X      while (*line_ptr++ != '\n');
  1312. X    }
  1313. X
  1314. X  return line_ptr;
  1315. X}
  1316. X
  1317. X/*
  1318. X * This routine outputs a three way diff passed as a list of
  1319. X * diff3_block's.
  1320. X * The argument MAPPING is indexed by external file number (in the
  1321. X * argument list) and contains the internal file number (from the
  1322. X * diff passed).  This is important because the user expects his
  1323. X * outputs in terms of the argument list number, and the diff passed
  1324. X * may have been done slightly differently (if the first argument in
  1325. X * the argument list was the standard input, for example).
  1326. X * REV_MAPPING is the inverse of MAPPING.
  1327. X */
  1328. Xvoid
  1329. Xoutput_diff3 (outputfile, diff, mapping, rev_mapping)
  1330. X     FILE *outputfile;
  1331. X     struct diff3_block *diff;
  1332. X     int mapping[3], rev_mapping[3];
  1333. X{
  1334. X  int i;
  1335. X  int oddoneout;
  1336. X  char *cp;
  1337. X  struct diff3_block *ptr;
  1338. X  int line;
  1339. X  int length;
  1340. X  int dontprint;
  1341. X  static int skew_increment[3] = { 2, 3, 1 }; /* 0==>2==>1==>3 */
  1342. X
  1343. X  for (ptr = diff; ptr; ptr = D_NEXT (ptr))
  1344. X    {
  1345. X      char x[2];
  1346. X
  1347. X      switch (ptr->correspond)
  1348. X    {
  1349. X    case DIFF_ALL:
  1350. X      x[0] = '\0';
  1351. X      dontprint = 3;    /* Print them all */
  1352. X      oddoneout = 3;    /* Nobody's odder than anyone else */
  1353. X      break;
  1354. X    case DIFF_1ST:
  1355. X    case DIFF_2ND:
  1356. X    case DIFF_3RD:
  1357. X      oddoneout = rev_mapping[(int) ptr->correspond - (int) DIFF_1ST];
  1358. X        
  1359. X      x[0] = oddoneout + '1';
  1360. X      x[1] = '\0';
  1361. X      dontprint = oddoneout==0;
  1362. X      break;
  1363. X    default:
  1364. X      fatal ("internal: Bad diff type passed to output");
  1365. X    }
  1366. X      fprintf (outputfile, "====%s\n", x);
  1367. X
  1368. X      /* Go 0, 2, 1 if the first and third outputs are equivalent. */
  1369. X      for (i = 0; i < 3;
  1370. X       i = (oddoneout == 1 ? skew_increment[i] : i + 1))
  1371. X    {
  1372. X      int realfile = mapping[i];
  1373. X      int
  1374. X        lowt = D_LOWLINE (ptr, realfile),
  1375. X        hight = D_HIGHLINE (ptr, realfile);
  1376. X      
  1377. X      fprintf (outputfile, "%d:", i + 1);
  1378. X      switch (lowt - hight)
  1379. X        {
  1380. X        case 1:
  1381. X          fprintf (outputfile, "%da\n", lowt - 1);
  1382. X          break;
  1383. X        case 0:
  1384. X          fprintf (outputfile, "%dc\n", lowt);
  1385. X          break;
  1386. X        default:
  1387. X          fprintf (outputfile, "%d,%dc\n", lowt, hight);
  1388. X          break;
  1389. X        }
  1390. X
  1391. X      if (i == dontprint) continue;
  1392. X
  1393. X      for (line = 0; line < hight - lowt + 1; line++)
  1394. X        {
  1395. X          fprintf (outputfile, "  ");
  1396. X          cp = D_RELNUM (ptr, realfile, line);
  1397. X          length = D_RELLEN (ptr, realfile, line);
  1398. X          fwrite (cp, sizeof (char), length, outputfile);
  1399. X        }
  1400. X      if (line != 0 && cp[length - 1] != '\n')
  1401. X        fprintf (outputfile, "\n\\ No newline at end of file\n");
  1402. X    }
  1403. X    }
  1404. X}
  1405. X
  1406. X/*
  1407. X * This routine outputs a diff3 set of blocks as an ed script.  This
  1408. X * script applies the changes between file's 2 & 3 to file 1.  It
  1409. X * takes the precise format of the ed script to be output from global
  1410. X * variables set during options processing.  Note that it does
  1411. X * destructive things to the set of diff3 blocks it is passed; it
  1412. X * reverses their order (this gets around the problems involved with
  1413. X * changing line numbers in an ed script).
  1414. X *
  1415. X * Note that this routine has the same problem of mapping as the last
  1416. X * one did; the variable MAPPING maps from file number according to
  1417. X * the argument list to file number according to the diff passed.  All
  1418. X * files listed below are in terms of the argument list.
  1419. X * REV_MAPPING is the inverse of MAPPING.
  1420. X *
  1421. X * The arguments FILE0, FILE1 and FILE2 are the strings to print
  1422. X * as the names of the three files.  These may be the actual names,
  1423. X * or may be the arguments specified with -L.
  1424. X *
  1425. X * Returns 1 if overlaps were found.
  1426. X */
  1427. X
  1428. Xint
  1429. Xoutput_diff3_edscript (outputfile, diff, mapping, rev_mapping,
  1430. X               file0, file1, file2)
  1431. X     FILE *outputfile;
  1432. X     struct diff3_block *diff;
  1433. X     int mapping[3], rev_mapping[3];
  1434. X     char *file0, *file1, *file2;
  1435. X{
  1436. X  int i;
  1437. X  int leading_dot;
  1438. X  int overlaps_found = 0;
  1439. X  struct diff3_block *newblock, *thisblock;
  1440. X
  1441. X  leading_dot = 0;
  1442. X
  1443. X  newblock = reverse_diff3_blocklist (diff);
  1444. X
  1445. X  for (thisblock = newblock; thisblock; thisblock = thisblock->next)
  1446. X    {
  1447. X      /* Must do mapping correctly.  */
  1448. X      enum diff_type type
  1449. X    = ((thisblock->correspond == DIFF_ALL) ?
  1450. X       DIFF_ALL :
  1451. X       ((enum diff_type)
  1452. X        (((int) DIFF_1ST)
  1453. X         + rev_mapping[(int) thisblock->correspond - (int) DIFF_1ST])));
  1454. X
  1455. X      /* If we aren't supposed to do this output block, skip it */
  1456. X      if (type == DIFF_2ND || type == DIFF_1ST
  1457. X      || (type == DIFF_3RD && dont_write_simple)
  1458. X      || (type == DIFF_ALL && dont_write_overlap))
  1459. X    continue;
  1460. X
  1461. X      if (flagging && type == DIFF_ALL)
  1462. X    /* Do special flagging */
  1463. X    {
  1464. X
  1465. X      /* Put in lines from FILE2 with bracket */
  1466. X      fprintf (outputfile, "%da\n",
  1467. X           D_HIGHLINE (thisblock, mapping[FILE0]));
  1468. X      fprintf (outputfile, "=======\n");
  1469. X      for (i = 0;
  1470. X           i < D_NUMLINES (thisblock, mapping[FILE2]);
  1471. X           i++)
  1472. X        {
  1473. X          if (D_RELNUM (thisblock, mapping[FILE2], i)[0] == '.')
  1474. X        { leading_dot = 1; fprintf(outputfile, "."); }
  1475. X          fwrite (D_RELNUM (thisblock, mapping[FILE2], i), sizeof (char),
  1476. X              D_RELLEN (thisblock, mapping[FILE2], i), outputfile);
  1477. X        }
  1478. X      fprintf (outputfile, ">>>>>>> %s\n.\n", file2);
  1479. X      overlaps_found = 1;
  1480. X
  1481. X      /* Add in code to take care of leading dots, if necessary. */
  1482. X      if (leading_dot)
  1483. X        {
  1484. X          fprintf (outputfile, "%d,%ds/^\\.\\./\\./\n",
  1485. X               D_HIGHLINE (thisblock, mapping[FILE0]) + 1,
  1486. X               (D_HIGHLINE (thisblock, mapping[FILE0])
  1487. X            + D_NUMLINES (thisblock, mapping[FILE2])));
  1488. X          leading_dot = 0;
  1489. X        }
  1490. X
  1491. X      /* Put in code to do initial bracket of lines from FILE0  */
  1492. X      fprintf (outputfile, "%da\n<<<<<<< %s\n.\n",
  1493. X           D_LOWLINE (thisblock, mapping[FILE0]) - 1,
  1494. X           file0);
  1495. X    }
  1496. X      else if (D_NUMLINES (thisblock, mapping[FILE2]) == 0)
  1497. X    /* Write out a delete */
  1498. X    {
  1499. X      if (D_NUMLINES (thisblock, mapping[FILE0]) == 1)
  1500. X        fprintf (outputfile, "%dd\n",
  1501. X             D_LOWLINE (thisblock, mapping[FILE0]));
  1502. X      else
  1503. X        fprintf (outputfile, "%d,%dd\n",
  1504. X             D_LOWLINE (thisblock, mapping[FILE0]),
  1505. X             D_HIGHLINE (thisblock, mapping[FILE0]));
  1506. X    }
  1507. X      else
  1508. X    /* Write out an add or change */
  1509. X    {
  1510. X      switch (D_NUMLINES (thisblock, mapping[FILE0]))
  1511. X        {
  1512. X        case 0:
  1513. X          fprintf (outputfile, "%da\n",
  1514. X               D_HIGHLINE (thisblock, mapping[FILE0]));
  1515. X          break;
  1516. X        case 1:
  1517. X          fprintf (outputfile, "%dc\n",
  1518. X               D_HIGHLINE (thisblock, mapping[FILE0]));
  1519. X          break;
  1520. X        default:
  1521. X          fprintf (outputfile, "%d,%dc\n",
  1522. X               D_LOWLINE (thisblock, mapping[FILE0]),
  1523. X               D_HIGHLINE (thisblock, mapping[FILE0]));
  1524. X          break;
  1525. X        }
  1526. X      for (i = 0;
  1527. X           i < D_NUMLINES (thisblock, mapping[FILE2]);
  1528. X           i++)
  1529. X        {
  1530. X          if (D_RELNUM (thisblock, mapping[FILE2], i)[0] == '.')
  1531. X        { leading_dot = 1; fprintf (outputfile, "."); }
  1532. X          fwrite (D_RELNUM (thisblock, mapping[FILE2], i), sizeof (char),
  1533. X              D_RELLEN (thisblock, mapping[FILE2], i), outputfile);
  1534. X        }
  1535. X      fprintf (outputfile, ".\n");
  1536. X      
  1537. X      /* Add in code to take care of leading dots, if necessary. */
  1538. X      if (leading_dot)
  1539. X        {
  1540. X          fprintf (outputfile, "%d,%ds/^\\.\\./\\./\n",
  1541. X               D_HIGHLINE (thisblock, mapping[FILE0]) + 1,
  1542. X               (D_HIGHLINE (thisblock, mapping[FILE0])
  1543. X            + D_NUMLINES (thisblock, mapping[FILE2])));
  1544. X          leading_dot = 0;
  1545. X        }
  1546. X    }
  1547. X    }
  1548. X  if (finalwrite) fprintf (outputfile, "w\nq\n");
  1549. X  return overlaps_found;
  1550. X}
  1551. X
  1552. X/*
  1553. X * Read from COMMONFILE and output to OUTPUTFILE a set of diff3_ blocks DIFF
  1554. X * as a merged file.  This acts like 'ed file0 <[output_diff3_edscript]',
  1555. X * except that it works even for binary data or incomplete lines.
  1556. X *
  1557. X * As before, MAPPING maps from arg list file number to diff file number,
  1558. X * REV_MAPPING is its inverse,
  1559. X * and FILE0, FILE1, and FILE2 are the names of the files.
  1560. X *
  1561. X * Returns 1 if overlaps were found.
  1562. X */
  1563. X
  1564. Xint
  1565. Xoutput_diff3_merge (commonfile, outputfile, diff, mapping, rev_mapping,
  1566. X            file0, file1, file2)
  1567. X     FILE *commonfile, *outputfile;
  1568. X     struct diff3_block *diff;
  1569. X     int mapping[3], rev_mapping[3];
  1570. X     char *file0, *file1, *file2;
  1571. X{
  1572. X  int c, i;
  1573. X  int overlaps_found = 0;
  1574. X  struct diff3_block *b;
  1575. X  int linesread = 0;
  1576. X
  1577. X  for (b = diff; b; b = b->next)
  1578. X    {
  1579. X      /* Must do mapping correctly */
  1580. X      enum diff_type type
  1581. X    = ((b->correspond == DIFF_ALL) ?
  1582. X       DIFF_ALL :
  1583. X       ((enum diff_type)
  1584. X        (((int) DIFF_1ST)
  1585. X         + rev_mapping[(int) b->correspond - (int) DIFF_1ST])));
  1586. X
  1587. X      /* If we aren't supposed to do this output block, skip it.  */
  1588. X      if (type == DIFF_2ND || type == DIFF_1ST
  1589. X      || (type == DIFF_3RD && dont_write_simple)
  1590. X      || (type == DIFF_ALL && dont_write_overlap))
  1591. X    continue;
  1592. X
  1593. X      /* Copy I lines from common file.  */
  1594. X      i = D_LOWLINE (b, FILE0) - linesread - 1;
  1595. X      linesread += i;
  1596. X      while (0 <= --i)
  1597. X    {
  1598. X      while ((c = getc(commonfile)) != '\n')
  1599. X        {
  1600. X          if (c == EOF)
  1601. X        fatal ("input file shrank");
  1602. X          putc (c, outputfile);
  1603. X        }
  1604. X      putc (c, outputfile);
  1605. X    }
  1606. X
  1607. X      if (flagging && type == DIFF_ALL)
  1608. X    /* Do special flagging.  */
  1609. X    {
  1610. X      /* Put in lines from FILE0 with bracket.  */
  1611. X      fprintf (outputfile, "<<<<<<< %s\n", file0);
  1612. X      for (i = 0;
  1613. X           i < D_NUMLINES (b, mapping[FILE0]);
  1614. X           i++)
  1615. X        fwrite (D_RELNUM (b, mapping[FILE0], i), sizeof (char),
  1616. X            D_RELLEN (b, mapping[FILE0], i), outputfile);
  1617. X      fprintf (outputfile, "=======\n");
  1618. X      overlaps_found = 1;
  1619. X    }
  1620. X
  1621. X      /* Put in lines from FILE2.  */
  1622. X      for (i = 0;
  1623. X       i < D_NUMLINES (b, mapping[FILE2]);
  1624. X       i++)
  1625. X    fwrite (D_RELNUM (b, mapping[FILE2], i), sizeof (char),
  1626. X        D_RELLEN (b, mapping[FILE2], i), outputfile);
  1627. X
  1628. X      if (flagging && type == DIFF_ALL)
  1629. X    fprintf (outputfile, ">>>>>>> %s\n", file2);
  1630. X
  1631. X      /* Skip I lines in common file.  */
  1632. X      i = D_NUMLINES (b, FILE0);
  1633. X      linesread += i;
  1634. X      while (0 <= --i)
  1635. X    while ((c = getc(commonfile)) != '\n')
  1636. X      if (c == EOF)
  1637. X        {
  1638. X          if (i || b->next)
  1639. X        fatal ("input file shrank");
  1640. X          return overlaps_found;
  1641. X        }
  1642. X    }
  1643. X  /* Copy rest of common file.  */
  1644. X  while ((c = getc (commonfile)) != EOF)
  1645. X    putc (c, outputfile);
  1646. X  return overlaps_found;
  1647. X}
  1648. X
  1649. X/*
  1650. X * Reverse the order of the list of diff3 blocks.
  1651. X */
  1652. Xstruct diff3_block *
  1653. Xreverse_diff3_blocklist (diff)
  1654. X     struct diff3_block *diff;
  1655. X{
  1656. X  register struct diff3_block *tmp, *next, *prev;
  1657. X
  1658. X  for (tmp = diff, prev = (struct diff3_block *) 0;
  1659. X       tmp; tmp = next)
  1660. X    {
  1661. X      next = tmp->next;
  1662. X      tmp->next = prev;
  1663. X      prev = tmp;
  1664. X    }
  1665. X  
  1666. X  return prev;
  1667. X}
  1668. X
  1669. Xint
  1670. Xmyread (fd, ptr, size)
  1671. X     int fd, size;
  1672. X     char *ptr;
  1673. X{
  1674. X  int result = read (fd, ptr, size);
  1675. X  if (result < 0)
  1676. X    perror_with_exit ("Read failed");
  1677. X  return result;
  1678. X}
  1679. X
  1680. XVOID *
  1681. Xxmalloc (size)
  1682. X     int size;
  1683. X{
  1684. X  VOID *result = (VOID *) malloc (size ? size : 1);
  1685. X  if (!result)
  1686. X    fatal ("Malloc failed");
  1687. X  return result;
  1688. X}
  1689. X
  1690. XVOID *
  1691. Xxrealloc (ptr, size)
  1692. X     VOID *ptr;
  1693. X     int size;
  1694. X{
  1695. X  VOID *result = (VOID *) realloc (ptr, size ? size : 1);
  1696. X  if (!result)
  1697. X    fatal ("Malloc failed");
  1698. X  return result;
  1699. X}
  1700. X
  1701. Xfatal (string)
  1702. X     char *string;
  1703. X{
  1704. X  fprintf (stderr, "%s: %s\n", argv0, string);
  1705. X  exit (2);
  1706. X}
  1707. X
  1708. Xperror_with_exit (string)
  1709. X     char *string;
  1710. X{
  1711. X  perror (string);
  1712. X  exit (2);
  1713. X}
  1714. END_OF_FILE
  1715. if test 46642 -ne `wc -c <'diff3.c'`; then
  1716.     echo shar: \"'diff3.c'\" unpacked with wrong size!
  1717. fi
  1718. # end of 'diff3.c'
  1719. fi
  1720. echo shar: End of archive 8 \(of 8\).
  1721. cp /dev/null ark8isdone
  1722. MISSING=""
  1723. for I in 1 2 3 4 5 6 7 8 ; do
  1724.     if test ! -f ark${I}isdone ; then
  1725.     MISSING="${MISSING} ${I}"
  1726.     fi
  1727. done
  1728. if test "${MISSING}" = "" ; then
  1729.     echo You have unpacked all 8 archives.
  1730.     rm -f ark[1-9]isdone
  1731. else
  1732.     echo You still need to unpack the following archives:
  1733.     echo "        " ${MISSING}
  1734. fi
  1735. ##  End of shell archive.
  1736. exit 0
  1737.  
  1738. exit 0 # Just in case...
  1739.